
import { UtilsHelper } from "utils/position/UtilsHelper";
import { StructureEntity } from "../StructureEntity";
import { CoreLayout, CoreLayoutConfig } from "./corelayout";
import { generateUniqueId } from "utils/utils";
import { priority } from "utils/constants/definetypes";
import { BaseMinerial } from "utils/constants/globalconstant";
import { BASE_PRODUCE ,} from "../factory/constants";
import { ShortResource, SurplusResource,base_depo,depo_resoource,getDepoLevelResource, isNeedBaseResource } from "./constants";
import { PositionHelper } from "utils/position/PositionHelper";
import { FactoryTaskHelper } from "../factory/FactoryTaskHelper";
import { compact } from "lodash";
 
/**
 * 资源调度
 */

export   class CoreEntity<T extends IBaseMineMemory=IBaseMineMemory,V extends IRoomModuleInitializer=IRoomModuleInitializer>  extends StructureEntity<T,V>  implements ILinkModule
{
    private factoryId?:Id<StructureFactory>;
    private powerSpawnId?:Id<StructurePowerSpawn>;
    private nukerId?:Id<StructureNuker>;
    private linkId?:Id<StructureLink>;
    private containerId?:Id<StructureContainer>;
    private _managerPos!:RoomPosition;

    private transferCallback?:(task:ITask<ICreepTaskData<"transportAccurate">>)=>void;
    public get ManagerPosition()
    {
        return this._managerPos;
    }
    /**
     * 建筑属性
     * --------------------------------------------------------------------------------------
    */

    public initAttributes(): void {
        super.initAttributes();
        if(this._initializer.plan)
        {
            const terpos = this._initializer.plan.structures[STRUCTURE_TERMINAL][0];
            const factorypos = this._initializer.plan.structures[STRUCTURE_FACTORY][0];
            this._managerPos = PositionHelper.Create({roomName:this.roomName,x:(terpos.x+factorypos.x)/2,y:(terpos.y+factorypos.y)/2})
        }
        else 
        {
            this._managerPos = PositionHelper.addPosition(this._basepos,CoreLayoutConfig._WorkPos);
        }
        // this.room.memory.center = [ this._managerPos.x,this._managerPos.y];
        this.updateIdCache();
    }
      /**
     * ---------------------------------------------------------------------------------------------
     * 继承抽象方法
     */
    public updateMemory(): void 
    {
        // throw new Error("Method not implemented.");
        this.updateIdCache();
    }
    // 更新ID缓存
    private updateIdCache()
    {
        if(!this.factoryId)
        {
            this.factoryId = this.room.getStructures(STRUCTURE_FACTORY)[0]?.id
        }
        if(!this.powerSpawnId)
        {
            this.powerSpawnId = this.room.getStructures(STRUCTURE_POWER_SPAWN)[0]?.id
        }
        if(!this.nukerId)
        {
            this.nukerId = this.room.getStructures(STRUCTURE_NUKER)[0]?.id
        }
        if(!this.linkId)
        {
            this.linkId = this.room.getStructures(STRUCTURE_LINK).filter(e=>e.pos.distance(this.ManagerPosition)<=1)[0]?.id;
        }
        if(!this.containerId)
        {
            this.containerId = this.room.getStructures(STRUCTURE_CONTAINER).filter(e=>e.pos.distance(this.ManagerPosition)<=1)[0]?.id;
        }
    }
    get Storage():StructureStorage 
    {
        return this.room?.storage;
    }

    get Terminal():StructureTerminal 
    {
        return this.room?.terminal;
    }
    get Factory():StructureFactory|null
    {
        if(this.factoryId)
        {
            return this.room.getStructureById(this.factoryId)
        }
        return null;

    }
    get PowerSpawn():StructurePowerSpawn |null
    {
        if(this.powerSpawnId)
        {
            return this.room.getStructureById(this.powerSpawnId)
        }
        return null;

    }
    get Nuker():StructureNuker|null
    {
        if(this.nukerId)
        {
            return this.room.getStructureById(this.nukerId)
        }
        return null;

    }
    get Link():StructureLink|undefined
    {
        if(this.linkId)
        {
            return this.room.getStructureById(this.linkId) as StructureLink|undefined
        }
        return undefined;

    }
    get Container():StructureContainer|undefined
    {
        if(this.containerId)
        {
            return this.room.getStructureById(this.containerId) as StructureContainer|undefined
        }
        return undefined;
        // const ids =  this.getStructuresByRelative(STRUCTURE_LINK
 
    }
    /**
     * 资源查询相关
     * ----------------------------------------------------------------------------------
    */
    /**
    * 查询资源数量
    * @param ResType 
    * @returns 
    */
    public resourceCount(ResType:ResourceConstant)
    {
        let num1=0;
        let num2=0;
         if(this.Storage)
         {
            num1 = this.Storage.store.getUsedCapacity(ResType);
         }
         if(this.Terminal)
         {
              num2 = this.Terminal.store.getUsedCapacity(ResType);

         }
         return num1+num2;
    }
    /**
     * 空闲空间
    */
    public getStores(type:Required<IResource>):AnyStoreStructure[]
    {
        
        let stores:(StructureTerminal|StructureStorage)[]=[]
        if((type.resourceType == RESOURCE_ENERGY&& this.Terminal && this.Terminal.store.getUsedCapacity(RESOURCE_ENERGY)<80000 && this.Terminal.store.getFreeCapacity()>50000)
        ||
        COMMODITIES[type.resourceType as CommodityConstant]?.level
        )
        {
            // 优先存终端
            stores = [ this.Terminal,this.Storage]
        }
        else 
        {
            stores = [ this.Storage,this.Terminal]
        }
        for(const e of stores)
        {
            if(!e)
            {
                continue;
            }
            let free = e.store.getFreeCapacity(type.resourceType);
            if(free>=type.amount)
            {

                return [e]
            }
        }
        return []
    }
    /**
     * 可取资源
     * @param type 
     * @returns 
     */
    public getTakeStores(type:Required<IResource>)
    {
        let storagecount = 0;
        let terminalcount = 0;
        if(this.Storage)
        {
            storagecount = this.Storage.store.getUsedCapacity(type.resourceType);
            if(storagecount>=type.amount)
            {
                return [this.Storage]
            }
        }

        if(this.Terminal)
        {
            terminalcount = this.Terminal.store.getUsedCapacity(type.resourceType);
            if(terminalcount>=type.amount)
            {
                return [this.Terminal]
            }
        }
        if(storagecount+terminalcount>=type.amount)
        {
            if(this.Terminal && this.Storage)
            {
                if(this.Storage.store.getFreeCapacity(type.resourceType)>terminalcount)
                {
                    // 抛出事件需要转移资源
                   //  this.transferResource(this.Terminal,this.Storage,[{resourceType:type.resourceType,amount:terminalcount}],1);
                    return [this.Storage]
                }
                if(this.Terminal.store.getFreeCapacity(type.resourceType)>storagecount)
                {
                    // 抛出事件需要转移资源
                    // this.transferResource(this.Storage,this.Terminal,[{resourceType:type.resourceType,amount:storagecount}],1);
                    return [this.Terminal]
                }
            }
        }
        return [];
    }
    public freeSpace()
    {
         if(this.Storage)
         {
            const num = this.Storage.store.getFreeCapacity();

            if(this.Terminal)
            {
                const num2 = this.Terminal.store.getFreeCapacity();
                return  num2+num;
            }
            return num;
         }
         return 0;
    }
    /**
     * 工厂是否可以生产了
     * @param targetResource 
     * @returns 
     */
    public isProduceReady(targetResource: CommodityConstant,time:number=1):boolean 
    {
        const subconstants = COMMODITIES[targetResource].components;
        for(const key in subconstants)
        {
            const type = key as FactoryResourceType;
            if((this.Factory?.store.getUsedCapacity(type) as number)< (subconstants[type]))
            {
                return false;
            }
        }
        return true;
    }
    /**
     *
     * @param From
     * @param To
     * @param resource
     * @param priority
     * @returns false 失败 0失败 true 成功
     */

    public transferResource(From:AnyStoreStructure,To:AnyStoreStructure,resource:Required<IResource>[],priority:number,id?:string,callback?:Function):string|0
    {
        const format_id = `task_${From.structureType[0]}_${To.structureType[0]}`;
        if(this.room.findTaskById(format_id,"core"))
        {
            return 0;
        }
        const transportparam:ITransportItem[]=[];
        const push_param=(from:AnyStoreStructure,to:  AnyStoreStructure,ResourceType:ResourceConstant,amount:number)=>
        {

            const item :ITransportItem={From: _.assign(from.pos,{id:from.id}),To:
            _.assign(to.pos,{id:to.id}),amount:amount,resourceType:ResourceType};
            transportparam.push(item);
        }
        for(const e of resource)
        {
            if(e.amount > 0)
            {
                push_param(From,To,e.resourceType,e.amount);
            }
        }
        const Taskarg:ICreepTaskData<"transportAccurate"> = 
        {
            type: "transportAccurate",
            arg: {
                List: transportparam
            },
            creeps: [],
            body: {},
            room: this.room.name,
            income: -1,
            disableSpawn: true,
            required: [
                [['manager'], 1,1]
            ],
            cost: 30
        }
       
        const task :ITask=
        {
            id:id?id:format_id,
            ttl: Math.ceil(_.sum(transportparam,e=>e.amount)/300)+200,
            priority:priority,
            type:"core",
            data:Taskarg,
            shard:1,
        }
        if(this.room.addNewTask(task))
        {
            this.transferCallback = callback as any;
            return task.id
            //action.arg.onComplete();
        }
        return 0
    }

    public onTransferComplete(task:ITask<ICreepTaskData<"transportAccurate">>)
    {
        // this.log('error','转移完成','执行回调')
        if(this.transferCallback)
        {
            this.transferCallback(task)
        }
    }

    public transferToLink(link:StructureLink )
    {
        if(!this.Link)
        {
            return false;
        }
        const res = {resourceType:RESOURCE_ENERGY,amount:this.Link.store.getFreeCapacity(RESOURCE_ENERGY)};
        const takes = this.getTakeStores(res);
        if(takes.length>0)
        {
            this.transferResource(takes[0],this.Link,[res],1,`L_To_L`,(arg:any)=>
            {
                this.Link?.transferEnergy(link);
            });
            return true;
        }
        return false;
    }
    /**
     * 判断是否正在转移中
     * @returns 
     */
    public isTransfering(taskId:string)
    {
        return this.room.findTaskById(taskId,"core")?true:false;
    }

    public makeFreeSpace(resourceType:FactoryResourceType,amount:number,components:Record<FactoryResourceType,number>)
    {

        if(this.Factory)
        {
            if(this.Factory.store.getFreeCapacity()>=amount)
            {
                return false;
            }
            //
             const unNeed: FactoryResourceType[]=[];

            for(let type in  this.Factory.store)
            {
                const curtye = type as FactoryResourceType;
                const hasnum = this.Factory.store.getUsedCapacity(curtye);
                if(components[curtye])
                {
                    if(components[curtye]<hasnum)
                    {
                        this.transferResource(this.Factory,this.Terminal,[{resourceType:curtye,amount:hasnum-components[curtye]}],1 ,`${this.roomName}_ClearFactory`);
                        return true;
                    }
                }
                else
                {
                    unNeed.push(type as FactoryResourceType);
                }
            }
            for(const e of unNeed)
            {
                this.transferResource(this.Factory,this.Terminal,[{resourceType:e,amount:this.Factory.store.getUsedCapacity(e)}],1,`${this.roomName}_ClearFactory` );
                return true;
            }
            return false;
        }
        // 异常

        throw new Error(`${this.GUID}  工厂不存在`);
    }
    /**
     * 从仓库取资源存到 store
     * @param store 
     * @param resource 
     * @param id 
     * @returns 
     */
    public transferInTask(store:AnyStoreStructure,resource:Required< IResource>,id?:string)
    {
        const objects =this.getTakeStores (resource);
        if(objects.length>0  )
        {
            return this.transferResource(objects[0],store,[resource],priority.F,id);
        }
        return false;
    }
      /**
     * 从 store 取资源 存到仓库
     * @param store 
     * @param resource 
     * @param id 
     * @returns 
     */
    public transferOutTask(store:AnyStoreStructure,resource:Required< IResource>,id?:string)
    {
        const objects =this.getStores (resource);
        if(objects.length>0  )
        {
            return this.transferResource(store,objects[0],[resource],priority.F,id);
        }
        return false;
    }
    public transferToFactoryTask(resource:Required< IResource>,id?:string)
    {
        this.log("info",`传入资源到工厂`,JSON.stringify(resource))
        if(this.Terminal && this.Factory)
        {
            const takeobj = this.getTakeStores (resource)  ;
            const gameobj = takeobj[0];
            // Memory.Debug[`factory InTask+${Game.time}`] = JSON.stringify(resource);
            if(takeobj.length>0 && gameobj)
            {
                return this.transferResource(gameobj,this.Factory,[resource],priority.F,id);            
            }
            else
            {
                // 基础矿物或者是我合成不了商品
                if(BaseMinerial.has(resource.resourceType))
                {
                    this.room.registerShortageResource(  
                        resource.resourceType,
                         10000
                     );
                    // 短缺
                    return 1
                }
                else
                {
                    const level = COMMODITIES[resource.resourceType as FactoryResourceType]?.level;
                    if(this.Factory?.level && level && this.Factory.level >level)
                    {
                         // 需要的资源等级比我的低
                        this.room.registerShortageResource(resource.resourceType,resource.amount);
                        this.room.registerNotify(Game.shard.name,{
                            type:'Distribute',
                            region:Game.shard.name,
                            room:this.room.name,
                            resourceType:resource.resourceType,
                            amount:resource.amount
                        })
                         return 1;
                    }
                    else
                    {
                        // 是我可以合成的资源.判断原材料是否充足
                        if(BASE_PRODUCE[resource.resourceType])
                        {
                            // 是区域商品基本合成材料,本房间资源不足.其他房间共享
                            if(this.resourceCount(BASE_PRODUCE[resource.resourceType])<resource.amount*5)
                            {
                                this.room.registerShortageResource(resource.resourceType,resource.amount*5);
                                this.room.registerNotify(Game.shard.name,{
                                    type:'Distribute',
                                    region:Game.shard.name,
                                    room:this.room.name,
                                    resourceType:resource.resourceType,
                                    amount:resource.amount
                                })
                                return 1;
                            }
                        }
                        return -1;
                    }

                }
            }
        }
        return 0;
    }
  /**----------------------------------------------------------------------------------
    */

  
    /**
     * 获取本房间内缺少得资源,只算原矿。
    */
    public getShortageResource():Record<ResourceConstant,number>
    {
        const resmap:Record<ResourceConstant,number>={} as Record<ResourceConstant,number>;
        // 1.基础资源
        for(let key in ShortResource)
        {
            const count = this.resourceCount(key  as ResourceConstant );
        
            if(count<ShortResource[key] )
            {
                // 贫瘠,原矿和bar都少才是缺矿
                resmap[key  as ResourceConstant]=ShortResource[key] ;
            }
        }
        // 2.只要没到8级能量低于150000就是缺少
        if(this.room.controller.level!=8 )
        {
             
            if(   this.resourceCount(RESOURCE_ENERGY)<300000)
            {
                resmap[RESOURCE_ENERGY] = 50000 ;
            }
        }
        else 
        {
            if(   this.resourceCount(RESOURCE_ENERGY)<90000)
            {
                resmap[RESOURCE_ENERGY] = 50000 ;
            }
            // power 小于5000就是缺
            if(   this.resourceCount(RESOURCE_POWER)<1000)
            {
                resmap[RESOURCE_POWER] = 5000;
            }
            if(this.Factory?.level)
            {
                for(let key in depo_resoource)
                {
                    const count = this.resourceCount(key  as ResourceConstant );
                    if(count<depo_resoource[key])
                    {
                        // 不足
                        resmap[key  as ResourceConstant]= 2000;
                    }
                }

                //  
            }
        }
        return resmap
    }
    /**
     * 获取本房间内富裕得资源,商品基本材料也要纳入共享的资源中。
    */
    public getSurplusResource():Record<ResourceConstant,number>
    {
        const resmap:Record<ResourceConstant,number>={} as Record<ResourceConstant,number>;


        // 1.基础资源
        for(let key in SurplusResource)
        {
            const count = this.resourceCount(key  as ResourceConstant );
            if(count>SurplusResource[key])
            {
                // 有富裕
                resmap[key  as ResourceConstant]=count-SurplusResource[key];
            }
        }

        // 判断是否有工厂.原矿高于
        if(this.Factory?.level)
        {
            // 有等级，只有我自己这个等级的是多余的
            const current_depos  = getDepoLevelResource()[this.Factory.level];
            // global.Log.Info(`${this.roomName} depo -> ${JSON.stringify(current_depos)}`);
            for(const item of current_depos)
            {
                const count = this.resourceCount(item );
                if(count>0)
                {
                    resmap[item]=count;
                }
            }

            // 不是所有的商品合成都需要 基本depo资源的
            for(let key in depo_resoource)
            {
                const count = this.resourceCount(key  as ResourceConstant );
                if(count>20000)
                {
                    // 多余
                    resmap[key  as ResourceConstant]= count-20000;
                }
            }
            {
                const res = getDepoLevelResource()[this.Factory.level];
                
                for(const item of res)
                {
                    const count = this.resourceCount(item );
                    if(count>0)
                    {
                        resmap[item]=count;
                    }
                }
            }
        }

        // {
        //     // // 有等级，还要根据商品的类型判断是否需要
        //     // 无等级。肯定是都不要的。
        //     for(let key in depo_resoource)
        //     {
        //         const count = this.resourceCount(key  as ResourceConstant );
        //         if(isNeedBaseResource(this.Factory?.level as number,key  as CommodityConstant))
        //         {
        //             if(count>depo_resoource[key])
        //             {
        //                 // 有富裕
        //                 resmap[key  as ResourceConstant]=count-depo_resoource[key];
        //             }
        //         }
        //         else
        //         {
        //             // 不需要基础资源的，全部共享出去
        //             resmap[key  as ResourceConstant]=count;
        //         }

        //     }
            
        // }
        return resmap
    }
    public isProduceResourceReady(target:CommodityConstant,time:number):boolean
    {
        // if(!COMMODITIES[target].level)
        {
            const childrecord = FactoryTaskHelper.getProductComposeRecord(target);
            for(const k in childrecord)
            {
                if(this.resourceCount(k as ResourceConstant)<childrecord[k as ResourceConstant]*time )
                {
                    // 子资源不足
                    return false;
                }
            }
            return true;
        }

    }
} 
